package com.cl.code;

import com.cl.code.entity.Expert;
import com.cl.code.entity.Major;

import java.util.*;
import java.util.stream.IntStream;

/**
 * @author chengliang
 * @since 1.0.0
 */
public class Main {

    public static void main(String[] args) {

        try {

            for (int a = 0; a < 100000; a++) {

                Map<Integer, Expert> expertMap = createExperts();
                Map<Integer, Major> majorMap = createMajors();

                // 为专家设置专业
                expertMap.get(1).setMajors(majorMap.get(1));
                expertMap.get(2).setMajors(majorMap.get(1), majorMap.get(2));
                expertMap.get(3).setMajors(majorMap.get(1), majorMap.get(2), majorMap.get(3));

                expertMap.get(4).setMajors(majorMap.get(1));
                expertMap.get(5).setMajors(majorMap.get(1), majorMap.get(2));
                expertMap.get(6).setMajors(majorMap.get(1), majorMap.get(2), majorMap.get(3));


                expertMap.get(7).setMajors(majorMap.get(1));
                expertMap.get(8).setMajors(majorMap.get(1), majorMap.get(2));
                expertMap.get(9).setMajors(majorMap.get(1), majorMap.get(2), majorMap.get(3));

                expertMap.get(10).setMajors(majorMap.get(1));
                expertMap.get(11).setMajors(majorMap.get(1), majorMap.get(2));
                expertMap.get(12).setMajors(majorMap.get(1), majorMap.get(2), majorMap.get(3));

                expertMap.get(13).setMajors(majorMap.get(2));
                expertMap.get(14).setMajors(majorMap.get(2), majorMap.get(3));

                expertMap.get(15).setMajors(majorMap.get(3));

                expertMap.get(16).setMajors(majorMap.get(1), majorMap.get(3));


//         按专业分组
                Map<Major, List<Expert>> majorGroup = majorGroup(expertMap);

                // 设置每个专业要抽取的专家数量
                Map<Major, Integer> majorExpertCount = new LinkedHashMap<>();
                majorExpertCount.put(majorMap.get(1), Integer.min(majorGroup.get(majorMap.get(1)).size(), 11));
                majorExpertCount.put(majorMap.get(2), Integer.min(majorGroup.get(majorMap.get(2)).size(),                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           2));
//        majorExpertCount.put(majorMap.get(3), Integer.min(majorGroup.get(majorMap.get(3)).size(), 3));
//        majorExpertCount.put(majorMap.get(4), Integer.min(majorGroup.get(majorMap.get(4)).size(), 2));
//        majorExpertCount.put(majorMap.get(5), Integer.min(majorGroup.get(majorMap.get(4)).size(), 1));

                // 按专业抽取专家
                Map<Major, List<Expert>> majorExpert = new LinkedHashMap<>();

                // 计算实际抽取人数
                int extractCount = Integer.min(majorExpertCount.values().stream().flatMapToInt(IntStream::of).sum(), expertMap.size());
                for (int i = 0; i < extractCount; i++) {
                    Optional<Map.Entry<Major, Integer>> majorIntegerEntry = majorExpertCount.entrySet().stream().filter(entry -> entry.getValue() > 0).findFirst();
                    if (majorIntegerEntry.isEmpty()) {
                        break;
                    }
                    Major major = majorIntegerEntry.get().getKey();
                    List<Expert> collect = expertMap.values().stream().filter(expert -> expert.getMajors().contains(major)).toList();
                    if (collect.isEmpty()) {
                        throw new RuntimeException("专家为空");
                    }
                    Expert expert = collect.get((int) (Math.random() * collect.size()));
                    expertMap.remove(expert.getId());
                    majorExpert.computeIfAbsent(major, k -> new ArrayList<>()).add(expert);
                    majorExpertCount.put(major, majorExpertCount.get(major) - 1);
                }
                long count = majorExpert.values().stream().mapToLong(Collection::size).sum();
                if (count == 15) {
                    System.out.println("count = " + count);
                } else {
                    System.out.println("count = " + count);
                }
            }
        } catch (Exception e) {

        }
    }

    public static Map<Integer, Expert> createExperts() {
        Map<Integer, Expert> expertHashMap = new HashMap<>();
        for (int i = 0; i < 16; i++) {
            int index = i + 1;
            Expert expert = new Expert(index, "expert" + index);
            expertHashMap.put(index, expert);
        }
        return expertHashMap;
    }

    public static Map<Integer, Major> createMajors() {
        Map<Integer, Major> majorHashMap = new HashMap<>();
        for (int i = 0; i < 5; i++) {
            int index = i + 1;
            Major major = new Major(index, "major" + index);
            majorHashMap.put(index, major);
        }
        return majorHashMap;
    }

    public static Map<Major, List<Expert>> majorGroup(Map<Integer, Expert> expertMap) {
        Map<Major, List<Expert>> majorExpertMap = new HashMap<>();

        for (Expert expert : expertMap.values()) {
            for (Major major : expert.getMajors()) {
                majorExpertMap.computeIfAbsent(major, k -> new ArrayList<>()).add(expert);
            }
        }

        return majorExpertMap;
    }

    public static int countExpertsInAllMajors(Collection<Expert> experts, Major... majors) {
        Set<Major> majorSet = new HashSet<>(Arrays.asList(majors));
        int count = 0;

        for (Expert expert : experts) {
            if (expert.getMajors().containsAll(majorSet)) {
                count++;
            }
        }

        return count;
    }

}